package cn.android666.libyuvdemo

import android.Manifest
import android.content.pm.PackageManager
import android.graphics.ImageFormat
import android.hardware.Camera
import android.os.Bundle
import android.view.SurfaceHolder
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
import cn.android666.libyuv.initLibrary
import cn.android666.libyuv.yv12RotateToNv21
import cn.android666.libyuvdemo.databinding.ActivityMainBinding
import cn.android666.timbertree.TimberUtil
import timber.log.Timber
import java.io.FileOutputStream
import java.io.IOException

class MainActivity : AppCompatActivity(), SurfaceHolder.Callback {

    private lateinit var binding: ActivityMainBinding
    private var count = 0
    private var count2 = 0
    private var totalCost = 0L
    private var start = 0L
    private var camera: Camera? = null
    private var recording = false
    private var yuvOutputStream: FileOutputStream? = null
    private var yuvFilePath: String? = null
    private var previewCallback: Camera.PreviewCallback? = null
    private lateinit var yuvBytes: ByteArray
    private val videoWidth = 640
    private val videoHeight = 480
    private val temp = ByteArray(videoWidth * videoHeight * 3 / 2)

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)

        binding.stopRecordButton.isEnabled = false

        binding.startRecordButton.setOnClickListener {
            startRecording()
        }

        binding.stopRecordButton.setOnClickListener {
            stopRecording()
        }

        binding.cameraPreview.holder.addCallback(this)

        // 检查权限
        if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED) {
            initializeCamera()
        } else {
            registerForActivityResult(ActivityResultContracts.RequestPermission()) {
                if (it) {
                    initializeCamera()
                }
            }.launch(Manifest.permission.CAMERA)
        }

        TimberUtil.logMethodName()
    }


    private fun initializeCamera() {
        try {
            camera = Camera.open()
            val parameters = camera?.parameters
            parameters?.setPreviewSize(videoWidth, videoHeight)
            yuvBytes = ByteArray(videoWidth * videoHeight * 3 / 2)
            parameters?.setPreviewFormat(ImageFormat.YV12)
            camera?.parameters = parameters
        } catch (e: Exception) {
            Timber.e(e, "无法打开相机")
        }
    }

    override fun surfaceCreated(holder: SurfaceHolder) {
        try {
            camera?.setPreviewDisplay(holder)
            camera?.startPreview()
        } catch (e: IOException) {
            Timber.e(e, "错误设置相机预览")
        }
    }


    override fun surfaceChanged(holder: SurfaceHolder, format: Int, width: Int, height: Int) {
        if (holder.surface == null) return

        try {
            camera?.stopPreview()
        } catch (e: Exception) {
            // 忽略
        }

        try {
            // 设置预览回调以获取YUV数据
            previewCallback = Camera.PreviewCallback { data, _ ->
                count++
                count2++

                if (start == 0L) {
                    start = System.currentTimeMillis()
                } else if (System.currentTimeMillis() - start >= 1000) {
                    Timber.d("帧率：${count}帧/s")
                    count = 0
                    start = 0L
                }

                val start = System.nanoTime()
                yv12RotateToNv21(data, yuvBytes, temp, videoWidth, videoHeight, 90)
                val cost = System.nanoTime() - start
                Timber.d("编码一帧耗时：%.3fms", (cost / 1000000.0))
                totalCost += cost

                if (count2 == 100) {
                    // 每编码一100帧耗时
                    Timber.d("编码100帧耗时：%.3fms", (totalCost / 1000000.0))
                    count2 = 0
                    totalCost = 0L
                }


                if (recording && yuvOutputStream != null) {
                    try {
                        yuvOutputStream?.write(yuvBytes)
                        stopRecording()
                    } catch (e: IOException) {
                        Timber.e(e, "写入YUV数据失败")
                    }
                }
            }

            val cameraInfo = Camera.CameraInfo()
            Camera.getCameraInfo(Camera.CameraInfo.CAMERA_FACING_BACK, cameraInfo)
            camera?.setDisplayOrientation(cameraInfo.orientation)
            camera?.setPreviewCallback(previewCallback)
            camera?.setPreviewDisplay(holder)
            camera?.startPreview()
        } catch (e: Exception) {
            Timber.e(e, "错误启动相机预览")
        }
    }

    override fun surfaceDestroyed(holder: SurfaceHolder) {
        camera?.stopPreview()
        camera?.release()
        camera = null
    }

    private fun startRecording() {
        if (recording) return

        // 创建YUV文件
        val fileName = "recording_${System.currentTimeMillis()}.yuv"
        yuvFilePath = getExternalFilesDir(null)?.absolutePath + "/" + fileName
        try {
            yuvOutputStream = FileOutputStream(yuvFilePath)
        } catch (e: IOException) {
            Timber.e(e, "创建YUV文件失败")
            return
        }

        binding.startRecordButton.isEnabled = false
        binding.stopRecordButton.isEnabled = true
        recording = true
    }

    private fun stopRecording() {
        if (!recording) return

        recording = false
        binding.startRecordButton.isEnabled = true
        binding.stopRecordButton.isEnabled = false

        try {
            yuvOutputStream?.close()
        } catch (e: IOException) {
            Timber.e(e, "关闭YUV文件失败")
        }
        yuvOutputStream = null
    }

    override fun onDestroy() {
        super.onDestroy()
        stopRecording()
        camera?.stopPreview()
        camera?.release()
        camera = null
        TimberUtil.logMethodName()
    }

    override fun onRestart() {
        super.onRestart()
        TimberUtil.logMethodName()
    }

    override fun onStart() {
        super.onStart()
        TimberUtil.logMethodName()
    }

    override fun onPause() {
        super.onPause()
        TimberUtil.logMethodName()
    }

    override fun onStop() {
        super.onStop()
        TimberUtil.logMethodName()
    }

    companion object {
        init {
            initLibrary()
        }
    }

}